package edu.cmu.javadb.index;

import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.util.*;

import edu.cmu.javadb.Attribute;
import edu.cmu.javadb.IndexInfo;
import edu.cmu.javadb.exceptions.*;
import edu.cmu.javadb.plan.condition.*;

public class TreeSetIndex<T> implements Index<T> {

	private TreeSet<T> set = null;
	private IndexInfo indexInfo = null;
	private Class type = null;
	
	public TreeSetIndex(Class type, IndexInfo indexInfo) {
		this.type = type;
		this.indexInfo = indexInfo;
		this.set = new TreeSet<T>(new IndexComparator<T>(indexInfo));
	}
	
	public void add(T r) {
		set.add(r);
//		System.out.println();
//		for (Annotation a : r.getClass().getAnnotations()) {
//			System.out.println(a.toString());
//		}
	}
	
	//assume fields in cond matches the fields in index
	
	private Condition findAnCondition(And and) throws ConditionNotSupportException {
		for (Condition c : and.getConditions()) {
			if (c instanceof Greater) {
				Greater g = (Greater)c;
				if (g.hasValue())
					return c;
			} else {
				throw new ConditionNotSupportException();
			}
		}
		return null;
	}
	
	//TODO deal with more cases.
	public List<T> find(Condition cond) throws ConditionNotSupportException {
		if (set.size() == 0)
			return null;
		List<T> res = new ArrayList<T>();		
		try {
			T st = (T) type.newInstance();
			if (cond instanceof Greater) {
				Greater g = ((Greater)cond);
				indexInfo.getAttributes().get(0).setValue(st, g.getRight());				
				SortedSet<T> s = set.tailSet(st);
				res.addAll(s);
			} else if (cond instanceof Equal) {
				Equal g = ((Equal)cond);
				indexInfo.getAttributes().get(0).setValue(st, g.getRight());				
				SortedSet<T> s = set.subSet(st, true, st, true);
				res.addAll(s);
			} else if (cond instanceof And) {
				Condition condToUse = findAnCondition((And) cond);
				List<T> tmp = find(condToUse);
				for (T t: tmp) {
					if (cond.satisfy(t)) {
						res.add(t);
					}
				}
			} else {
				throw new ConditionNotSupportException();
			}			
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}  catch (SecurityException e) {
			e.printStackTrace();
		}
	
		return res;
	}

	@Override
	public void remove(T r) {
		set.remove(r);		
	}
}
